package com.hptpd.questionnairesurvey.service.impl;

import com.google.common.collect.Maps;
import com.hptpd.questionnairesurvey.assets.Constant;
import com.hptpd.questionnairesurvey.component.PageResult;
import com.hptpd.questionnairesurvey.component.Result;
import com.hptpd.questionnairesurvey.domain.*;
import com.hptpd.questionnairesurvey.domain.question.BaseQuestion;
import com.hptpd.questionnairesurvey.domain.question.FillsUpQuestion;
import com.hptpd.questionnairesurvey.domain.question.SingleChoiceQuestion;
import com.hptpd.questionnairesurvey.repository.*;
import com.hptpd.questionnairesurvey.service.IQuestionnaireService;
import com.hptpd.questionnairesurvey.service.base.BaseServiceImpl;
import com.hptpd.questionnairesurvey.service.excel.ImportQuestionnaire;
import com.hptpd.questionnairesurvey.utils.AbstractMyBeanUtils;
import com.hptpd.questionnairesurvey.utils.DimensionalityVoRecursionUtil;
import com.hptpd.questionnairesurvey.vo.ChoiceVo;
import com.hptpd.questionnairesurvey.vo.DimensionalityVo;
import com.hptpd.questionnairesurvey.vo.QuestionVo;
import com.hptpd.questionnairesurvey.vo.QuestionnaireVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * \* Created with IntelliJ IDEA.
 * \* Date: 2019/9/17
 * \*
 * \* Description:
 * \
 *
 * @author walter_long
 */
@Service("iQuestionnaireService")
public class QuestionnaireServiceImpl extends BaseServiceImpl implements IQuestionnaireService {
    @Resource(name = "questionnaireRep")
    private QuestionnaireRep questionnaireRep;

    @Resource(name = "choiceRep")
    private ChoiceRep choiceRep;

    @Resource(name = "baseQuestionRep")
    private BaseQuestionRep baseQuestionRep;

    @Resource(name = "dimensionalityRep")
    private DimensionalityRep dimensionalityRep;

    @Resource(name = "userSurveyRep")
    private UserSurveyRep userSurveyRep;

    @Resource(name = "userRep")
    private UserRep userRep;

    @Resource
    private FillsUpRep fillsUpRep;

    @Resource
    private SingleChoiceRep singleChoiceRep;

    @Override
    public Result listQuestionnairesByPage(@NotNull Map<String, Object> paramMap, @NotNull Pageable pageable) {
        Page<Questionnaire> page = questionnaireRep.findByNameContainsAndDeletedIsNotAndStateContainsOrderByCreatedAtDesc((String) paramMap.get("name"), true, (String) paramMap.get("state"), pageable);
        return Result.ok(PageResult.setPageResult(pageable, page.getTotalElements(), QuestionnaireVo.convertQuestionnaire(page.getContent())));
    }

    @Override
    public Result deleteQuestionnaire(@NotNull QuestionnaireVo questionnaireVo) {
        Optional<Questionnaire> questionnaireOptional = questionnaireRep.findById(questionnaireVo.getId());
        if (!questionnaireOptional.isPresent()) {
            return Result.badArgumentValue();
        }
        Questionnaire questionnaire = questionnaireOptional.get();
        questionnaire.setDeleted(true);
        questionnaireRep.save(questionnaire);
        return Result.ok();
    }

    @Override
    public Result issueQuestionnaire(@NotNull QuestionnaireVo questionnaireVo) {
        Optional<Questionnaire> questionnaireOptional = questionnaireRep.findById(questionnaireVo.getId());
        if (!questionnaireOptional.isPresent()) {
            return Result.badArgumentValue();
        }
        Questionnaire questionnaire = questionnaireOptional.get();
        questionnaire.setState(Constant.QUESTIONNAIRE_ISSUE);
        questionnaireRep.save(questionnaire);
        return Result.ok();
    }

    @Override
    public Object getQuestionnaire(String name, boolean deleted) {
        return questionnaireRep.findByNameAndDeleted(name, deleted);
    }

    /**
     * 新建试卷
     *
     * @param questionnaireVo
     * @return
     */
    @Override
    public Result saveQuestionnaire(QuestionnaireVo questionnaireVo) {
        Questionnaire questionnaire = null;
        if (StringUtils.isNotBlank(questionnaireVo.getId())) {
            questionnaire = questionnaireRep.findQuestionnaireById(questionnaireVo.getId()).get();
        } else {
            questionnaire = new Questionnaire();
        }
        questionnaire.setName(questionnaireVo.getName());
        questionnaire.setState(Constant.QUESTIONNAIRE_NOTISSUE);
        questionnaire.setCreatedAt(new Date());
        questionnaire.setTag(questionnaireVo.getTag());
        questionnaire = questionnaireRep.save(questionnaire);

        for (DimensionalityVo dimensionVo :
                questionnaireVo.getDimensions()) {
            saveDimensionality(questionnaire, null, dimensionVo);
        }

        //把没和维度绑定的题目保存
        DimensionalityVoRecursionUtil dimensionalityVoRecursionUtil = new DimensionalityVoRecursionUtil();
        List<QuestionVo> questionVos = dimensionalityVoRecursionUtil.filterNoDimensionalityQuestion(questionnaireVo.getDimensions(), questionnaireVo.getQuestions());
        saveQuestionVos(questionVos, null, questionnaire);

        QuestionnaireVo questionnaireVo1 = new QuestionnaireVo();
        AbstractMyBeanUtils.copyProperties(questionnaire, questionnaireVo1);
        return Result.ok(questionnaireVo1);
    }

    @Override
    public Result getQuestionnaireById(String id) {
        QuestionnaireVo questionnaireVo = null;
        Optional<Questionnaire> questionnaire = questionnaireRep.findQuestionnaireById(id);
        if (questionnaire.isPresent()) {
            questionnaireVo = QuestionnaireVo.convertQuestionnaire(questionnaire.get());
            questionnaireVo.sortQuestions();
            return Result.ok(questionnaireVo);
        }
        return Result.badArgument();
    }

    @Override
    public Result getQuestionnaireByUserSurveyId(@NotNull String userId, @NotNull String userSurveyId) {
        if (userId.isEmpty() || userSurveyId.isEmpty()) {
            return Result.badArgumentValue();
        }
        Optional<User> userOptional = userRep.findById(userId);
        Optional<UserSurvey> userSurveyOptional = userSurveyRep.findById(userSurveyId);
        if (!userOptional.isPresent() || !userSurveyOptional.isPresent() || !userId.equals(userSurveyOptional.get().getUser().getId())) {
            return Result.badArgumentValue();
        }
        return this.getQuestionnaireById(userSurveyOptional.get().getSurvey().getQuestionnaire().getId());
    }

    /**
     * 删除维度
     *
     * @param id 维度id
     * @return
     */
    @Override
    public void deleteDimension(String id) {
        Dimensionality dimensionality = dimensionalityRep.findDimensionalityById(id);
        if (dimensionality.getChildDimensionalities().isEmpty()) {
            dimensionalityRep.delete(dimensionality);
            return;
        }
        for(Dimensionality dimension : dimensionality.getChildDimensionalities()) {
            deleteDimension(dimension.getId());
        }
    }

    /**
     * 删除单选题
     *
     * @param id 单选题id
     * @return
     */
    @Override
    public void deleteSingleQuestion(String id){
        BaseQuestion baseQuestion = singleChoiceRep.getSingleChoiceQuestionById(id);
        List<Choice> choices = choiceRep.findChoicesByBaseQuestion(baseQuestion);
        for (Choice choice : choices) {
            choiceRep.delete(choice);
        }
        singleChoiceRep.deleteById(id);
    }

    /**
     * 删除填空题
     *
     * @param id
     * @return
     */
    @Override
    public void deleteFillQuestion(String id) {
        Optional<FillsUpQuestion> optionalFillsUpQuestion = fillsUpRep.findById(id);
        if (!optionalFillsUpQuestion.isPresent()) {
            return;
        }
        FillsUpQuestion fillsUpQuestion = optionalFillsUpQuestion.get();
        fillsUpRep.delete(fillsUpQuestion);
    }

    /**
     * 删除单选题选项
     *
     * @param id
     * @return
     */
    @Override
    public void deleteChoice(String id){
        choiceRep.deleteById(id);
    }

    /**
     * 导入试卷
     *
     * @param excelFile
     */
    @Override
    public Result importQuestionnaire(MultipartFile excelFile) {
        ImportQuestionnaire importQuestionnaire = new ImportQuestionnaire(
                excelFile, questionnaireRep, baseQuestionRep, choiceRep);
        if (importQuestionnaire.parseQuestions()) {
            return Result.ok(QuestionnaireVo.convertQuestionnaire(importQuestionnaire.getQuestionnaire()));
        }
        return Result.ok();
    }

    @Override
    public Result copyQuestionnaire(QuestionnaireVo questionnaireVo) {
        //赋值dimensionTempTag字段，后面的存储会有根据该字段判断的逻辑
        this.addDimensionTempTag2QuestionnaireVo(questionnaireVo);

        List<DimensionalityVo> dimensionalityVos = questionnaireVo.getDimensions();
        List<QuestionVo> questionVos = questionnaireVo.getQuestions();
        if (null != questionVos) {
            questionVos.forEach(v -> {
                List<ChoiceVo> choiceVos = v.getChoiceVos();
                if (null != choiceVos) {
                    choiceVos.forEach(val -> {
                        val.setId(null);
                    });
                }
                v.setId(null);
            });
        }
        if (null != dimensionalityVos) {
            dimensionalityVos.forEach(this::clearDimensionalityVosId);
        }
        questionnaireVo.setId(null);
        return Result.ok(saveQuestionnaire(questionnaireVo));
    }

    private void addDimensionTempTag2QuestionnaireVo(QuestionnaireVo questionnaireVo) {
        Map<Integer, String> map = Maps.newHashMap();
        List<DimensionalityVo> dimensionalityVos = questionnaireVo.getDimensions();
        List<QuestionVo> questionVos = questionnaireVo.getQuestions();
        if (null != dimensionalityVos) {
            dimensionalityVos.forEach(v -> {
                this.addDimensionTempTag2DimensionalityVo(map, v);
            });
        }
        if (null != questionVos) {
            questionVos.forEach(v -> {
                if (null != v.getSort()) {
                    v.setDimensionTempTag(map.get(v.getSort()));
                }
            });
        }
    }

    private void addDimensionTempTag2DimensionalityVo(Map<Integer, String> map, DimensionalityVo dimensionalityVo) {
        if (null == dimensionalityVo) {
            return;
        }
        dimensionalityVo.setDimensionTempTag(dimensionalityVo.getId());
        List<QuestionVo> questionVos = dimensionalityVo.getQuestions();
        if (null != questionVos) {
            questionVos.forEach(v -> {
                v.setDimensionTempTag(dimensionalityVo.getId());
                map.put(v.getSort(), dimensionalityVo.getId());
            });
        }
        List<DimensionalityVo> dimensionalityVos = dimensionalityVo.getChildren();
        if (null == dimensionalityVos || dimensionalityVos.isEmpty()) {
            return;
        }
        dimensionalityVos.forEach(v -> {
            this.addDimensionTempTag2DimensionalityVo(map, v);
        });
    }

    private void clearDimensionalityVosId(DimensionalityVo dimensionalityVo) {
        if (null == dimensionalityVo) {
            return;
        }
        dimensionalityVo.setId(null);
        List<QuestionVo> questionVos = dimensionalityVo.getQuestions();
        if (null != questionVos) {
            questionVos.forEach(v -> {
                List<ChoiceVo> choiceVos = v.getChoiceVos();
                if (null != choiceVos) {
                    choiceVos.forEach(val -> {
                        val.setId(null);
                    });
                }
                v.setId(null);
            });
        }
        List<DimensionalityVo> dimensionalityVos = dimensionalityVo.getChildren();
        if (null == dimensionalityVos || dimensionalityVos.isEmpty()) {
            return;
        }
        dimensionalityVos.forEach(this::clearDimensionalityVosId);
    }

    /**
     * 递归保存维度树形结构
     *
     * @param questionnaire
     * @param parent
     * @param dimensionalityVo
     * @return
     */
    private Dimensionality saveDimensionality(Questionnaire questionnaire, Dimensionality parent,
                                              DimensionalityVo dimensionalityVo) {
        if (questionnaire == null) {
            return null;
        }
        Dimensionality dimensionality;
        if (StringUtils.isBlank(dimensionalityVo.getId())) {
            dimensionality = new Dimensionality();
        } else {
            dimensionality = dimensionalityRep.findDimensionalityById(dimensionalityVo.getId());
        }
        dimensionality.setName(dimensionalityVo.getName());
        dimensionality.setWeight(dimensionalityVo.getWeight());
        dimensionality.setSort(dimensionalityVo.getSort());
        dimensionality.setQuestionnaire(questionnaire);
        dimensionality.setParentDimensionality(parent);
        dimensionality = dimensionalityRep.save(dimensionality);

        saveQuestionVos(dimensionalityVo.getQuestions(), dimensionality, questionnaire);

        if (dimensionalityVo.getChildren() != null) {
            for (DimensionalityVo dimensionVo : dimensionalityVo.getChildren()) {
                saveDimensionality(questionnaire, dimensionality, dimensionVo);
            }
        }
        return dimensionality;
    }

    /**
     * 保存填空题
     *
     * @param dimensionality
     * @param questionVo
     * @return
     */
    private FillsUpQuestion saveFillQuestion(Dimensionality dimensionality, QuestionVo questionVo, Questionnaire questionnaire) {
        FillsUpQuestion fillsUpQuestion = null;
        if (StringUtils.isBlank(questionVo.getId())) {
            fillsUpQuestion = new FillsUpQuestion();
        } else {
            fillsUpQuestion = fillsUpRep.getFillsUpQuestionById(questionVo.getId());
        }
        AbstractMyBeanUtils.copyProperties(questionVo, fillsUpQuestion);
        fillsUpQuestion.setDimensionality(dimensionality);
        fillsUpQuestion.setQuestionnaire(questionnaire);
        fillsUpQuestion = fillsUpRep.save(fillsUpQuestion);
        return fillsUpQuestion;
    }

    /**
     * 保存单选题
     *
     * @param dimensionality
     * @param questionVo
     * @return
     */
    private SingleChoiceQuestion saveSingleQuestion(Dimensionality dimensionality, QuestionVo questionVo, Questionnaire questionnaire) {
        SingleChoiceQuestion singleChoiceQuestion = null;
        if (StringUtils.isBlank(questionVo.getId())) {
            singleChoiceQuestion = new SingleChoiceQuestion();
        } else {
            singleChoiceQuestion = singleChoiceRep.getSingleChoiceQuestionById(questionVo.getId());
        }
        AbstractMyBeanUtils.copyProperties(questionVo, singleChoiceQuestion);
        singleChoiceQuestion.setDimensionality(dimensionality);
        singleChoiceQuestion.setQuestionnaire(questionnaire);
        singleChoiceQuestion = singleChoiceRep.save(singleChoiceQuestion);
        for (ChoiceVo choiceVo : questionVo.getChoiceVos()) {
            saveChoice(singleChoiceQuestion, choiceVo);
        }
        return singleChoiceQuestion;
    }

    /**
     * 保存选择题选项
     *
     * @param singleChoiceQuestion
     * @param choiceVo
     * @return
     */
    private Choice saveChoice(SingleChoiceQuestion singleChoiceQuestion, ChoiceVo choiceVo) {
        Choice choice = null;
        if (StringUtils.isBlank(choiceVo.getId())) {
            choice = new Choice();
        } else {
            choice = choiceRep.getChoiceById(choiceVo.getId());
        }
        AbstractMyBeanUtils.copyProperties(choiceVo, choice);
        choice.setBaseQuestion(singleChoiceQuestion);
        choice = choiceRep.save(choice);
        return choice;
    }

    private void saveQuestionVos(List<QuestionVo> questionVos, Dimensionality dimensionality, Questionnaire questionnaire) {
        for (QuestionVo questionVo :
                questionVos) {
            if (questionVo.getType().equals(Constant.QUESTION_TYPE_SINGLE)) {
                saveSingleQuestion(dimensionality, questionVo, questionnaire);
            } else {
                saveFillQuestion(dimensionality, questionVo, questionnaire);
            }
        }
    }
}
